/*
 * Copyright 2006 Matt Jensen
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.spectaql.internal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.spectaql.*;
import org.spectaql.internal.query.QueryContextImpl;
import org.spectaql.metadata.PersistenceMetadata;
import org.spectaql.metadata.EntityMetadata;

/**
 * <p>
 * <code>SpectaqlContextImpl</code> is the internal implementation of the {@link SpectaqlContext} interface.
 * </p>
 * <p>
 * <strong>Thread Safety:</strong> Instances of this class are safe for concurrent access. 
 * </p>
 */
class SpectaqlContextImpl implements SpectaqlContext, SpectaqlContextInternal
{
    private static Log LOG = LogFactory.getLog(SpectaqlContextImpl.class);

    /**
     * <p>
     * The proxy instantiation strategy.
     * </p>
     */
    private final ProxyInstantiationStrategy m_proxyInstantiationStrategy;

    /**
     * <p>
     * The persistence metadata. 
     * </p>
     */
    private final PersistenceMetadata m_persistenceMetadata;

    /**
     * <p>
     * Construct a {@link SpectaqlContextImpl} instance.
     * </p>
     *
     * @param proxyInstantiationStrategy the proxy instantiation strategy.
     * @param persistenceAdapter the persistence metadata source.
     */
    public SpectaqlContextImpl(final ProxyInstantiationStrategy proxyInstantiationStrategy,
                               final PersistenceAdapter persistenceAdapter)
    {
        super();
        assert null != proxyInstantiationStrategy : "The [proxyInstantiationStrategy] argument cannot be null.";
        assert null != persistenceAdapter : "The [persistenceMetadataSource] argument cannot be null.";

        m_proxyInstantiationStrategy = proxyInstantiationStrategy;
        m_persistenceMetadata = persistenceAdapter.getPersistenceMetadata();
    }

    /* inherit javadoc */
    public Query createQuery(final QueryCallback queryCallback)
    {
        // Create a query context.
        final QueryContext queryContext = new QueryContextImpl(this);

        // Invoke the callback to configure the query.
        final Query result = queryCallback.buildQuery(queryContext);
        if (LOG.isDebugEnabled())
        {
            LOG.debug(String.format("Returning query [%s] from query context [%s].", result, queryContext));
        }
        return result;
    }

    /* inherit javadoc */
    @SuppressWarnings("unchecked")
    public <T> T createProxy(final Class<T> entityClass, final Object internalHandler)
    {
        // Get the entity metadata.
        final EntityMetadata entityMetadata = m_persistenceMetadata.getEntity(entityClass);

        // Create the proxy.
        return (T)m_proxyInstantiationStrategy.createProxy(entityMetadata, internalHandler);
    }

    /* inherit javadoc */
    public PersistenceMetadata getPersistenceMetadata()
    {
        return m_persistenceMetadata;
    }

    /* inherit javadoc */
    public boolean isEntityClass(final Class<?> clazz)
    {
        return m_persistenceMetadata.isEntityClass(clazz);
    }
}
